home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / edit / tde40.zip / dirlist.c < prev    next >
C/C++ Source or Header  |  1994-06-05  |  66KB  |  2,021 lines

  1. /*
  2.  * I wrote this function because I'm so stupid, I constantly forget
  3.  *  file names and directory stuff.  The main function prompts for a
  4.  *  subdirectory name or a search path.  The default search path is the
  5.  *  cwd (current working directory).  In addition to being stupid, I'm also
  6.  *  lazy.  If the user types a subdirectory name, I think we can assume he
  7.  *  wants to list all files w/o having to type *.*   Let's save the cwd on
  8.  *  whatever drive the user wishes to search, so we can restore it we get
  9.  *  thru dir'ing.  Use the standard DOS functions to get and set directories.
  10.  *
  11.  * The search pattern can contain wild card chars, valid file names, or a
  12.  *  valid subdirectory name.
  13.  *
  14.  * Being that TDE 2.2 now handles binary files, lets make .EXE and .COM files
  15.  *  autoload in binary mode.
  16.  *
  17.  * Before matching files are displayed on the screen, file names are sorted
  18.  *  using the easy-to-implement and fairly fast Shellsort algorithm.
  19.  *
  20.  * See:
  21.  *
  22.  *   Donald Lewis Shell, "A High-Speed Sorting Procedure."  _Communications of
  23.  *     the ACM_ 2 (No. 2): 30-32, 1959.
  24.  *
  25.  * See also:
  26.  *
  27.  *   Donald Ervin Knuth, _The Art of Computer Programming; Volume 3:  Sorting
  28.  *     and Searching_, Addison-Wesley, Reading, Mass., 1973, Chapter 5,
  29.  *     "Sorting", pp 84-95.  ISBN 0-201-03803-X.
  30.  *
  31.  *   Robert Sedgewick, _Algorithms in C_, Addison-Wesley, Reading, Mass.,
  32.  *     1990, Chapter 8, "Elementary Sorting Methods", pp 107-111.
  33.  *     ISBN 0-201-51425-7.
  34.  *
  35.  *
  36.  * New editor name:  TDE, the Thomson-Davis Editor.
  37.  * Author:           Frank Davis
  38.  * Date:             June 5, 1991, version 1.0
  39.  * Date:             July 29, 1991, version 1.1
  40.  * Date:             October 5, 1991, version 1.2
  41.  * Date:             January 20, 1992, version 1.3
  42.  * Date:             February 17, 1992, version 1.4
  43.  * Date:             April 1, 1992, version 1.5
  44.  * Date:             June 5, 1992, version 2.0
  45.  * Date:             October 31, 1992, version 2.1
  46.  * Date:             April 1, 1993, version 2.2
  47.  * Date:             June 5, 1993, version 3.0
  48.  * Date:             August 29, 1993, version 3.1
  49.  * Date:             November 13, 1993, version 3.2
  50.  * Date:             June 5, 1994, version 4.0
  51.  *
  52.  * This code is released into the public domain, Frank Davis.
  53.  *    You may distribute it freely.
  54.  */
  55.  
  56. #include "tdestr.h"
  57. #include "common.h"
  58. #include "define.h"
  59. #include "tdefunc.h"
  60.  
  61.  
  62. #if defined( __UNIX__ )
  63. /*
  64.  **********************************************************************
  65.  ******************************  PART 1  ******************************
  66.  **********************************************************************
  67.  *
  68.  * Let's try to make unix have the look and feel of a PC.
  69.  */
  70.  
  71.  
  72. /*
  73.  * Name:    dir_help
  74.  * Purpose: To prompt the user and list the directory contents
  75.  * Date:    November 13, 1993
  76.  * Passed:  window:  pointer to current window
  77.  */
  78. int  dir_help( TDE_WIN *window )
  79. {
  80. char dname[PATH_MAX+2]; /* directory search pattern */
  81. char stem[PATH_MAX+2];  /* directory stem */
  82. int  rc;
  83. int  file_mode;
  84. int  bin_length;
  85. int  prompt_line;
  86.  
  87.    if (window != NULL) {
  88.       entab_linebuff( );
  89.       if (un_copy_line( window->ll, window, TRUE ) == ERROR)
  90.          return( ERROR );
  91.       prompt_line = window->bottom_line;
  92.    } else
  93.       prompt_line = g_display.nlines;
  94.  
  95.    /*
  96.     * search path or pattern
  97.     */
  98.    dname[0] = '\0';
  99.    rc = get_name( dir1, prompt_line, dname, g_display.message_color );
  100.  
  101.    if (rc == OK) {
  102.       if (validate_path( dname, stem ) == OK) {
  103.          rc = list_and_pick( dname, stem, window );
  104.          if (access( dname, F_OK ) == ERROR)
  105.             rc = ERROR;
  106.  
  107.          /*
  108.           * if everything is everything, load in the file selected by user.
  109.           *  dname contains complete path to file.  stem contains file name.
  110.           */
  111.          if (rc == OK) {
  112.             if (access( dname, X_OK ) != ERROR) {
  113.                file_mode = BINARY;
  114.                bin_length = g_status.file_chunk;
  115.             } else {
  116.                file_mode = TEXT;
  117.                bin_length = 0;
  118.             }
  119.             if (window != NULL)
  120.                attempt_edit_display( dname, LOCAL, file_mode, bin_length );
  121.             else
  122.                attempt_edit_display( dname, GLOBAL, file_mode, bin_length );
  123.          }
  124.       } else {
  125.          /*
  126.           * invalid path or file name
  127.           */
  128.          error( WARNING,
  129.                 window != NULL ? window->bottom_line : g_display.nlines, dir2 );
  130.          rc = ERROR;
  131.       }
  132.    }
  133.    return( rc );
  134. }
  135.  
  136.  
  137. /*
  138.  * Name:    dir_help_name
  139.  * Purpose: Use name entered by user
  140.  * Date:    November 13, 1993
  141.  * Passed:  window:  pointer to current window
  142.  */
  143. int  dir_help_name( TDE_WIN *window, char *name )
  144. {
  145. char dname[PATH_MAX+2]; /* directory search pattern */
  146. char stem[PATH_MAX+2];  /* directory stem */
  147. int  rc;
  148. int  file_mode;
  149. int  bin_length;
  150. int  prompt_line;
  151.  
  152.    rc = OK;
  153.    if (window != NULL) {
  154.       entab_linebuff( );
  155.       if (un_copy_line( window->ll, window, TRUE ) == ERROR)
  156.          return( ERROR );
  157.       prompt_line = window->bottom_line;
  158.    } else
  159.       prompt_line = g_display.nlines;
  160.  
  161.    /*
  162.     * search path or pattern
  163.     */
  164.    strcpy( dname, name );
  165.  
  166.    if (rc == OK) {
  167.       if ((rc = validate_path( dname, stem )) == OK) {
  168.          rc = list_and_pick( dname, stem, window );
  169.          if (access( dname, F_OK ) == ERROR)
  170.             rc = ERROR;
  171.  
  172.          /*
  173.           * if everything is everything, load in the file selected by user.
  174.           *  dname contains complete path to file.  stem contains file name.
  175.           */
  176.          if (rc == OK) {
  177.             if (access( dname, X_OK ) != ERROR) {
  178.                file_mode = BINARY;
  179.                bin_length = g_status.file_chunk;
  180.             } else {
  181.                file_mode = TEXT;
  182.                bin_length = 0;
  183.             }
  184.             if (window != NULL)
  185.                attempt_edit_display( dname, LOCAL, file_mode, bin_length );
  186.             else
  187.                attempt_edit_display( dname, GLOBAL, file_mode, bin_length );
  188.          }
  189.       } else
  190.          /*
  191.           * invalid path or file name
  192.           */
  193.          error( WARNING,
  194.                 window != NULL ? window->bottom_line : g_display.nlines, dir2 );
  195.    }
  196.    return( rc );
  197. }
  198.  
  199.  
  200. /*
  201.  * Name:    validate_path
  202.  * Purpose: make sure we got a valid search pattern or subdirectory
  203.  * Date:    November 13, 1993
  204.  * Passed:  dname: search path entered by user
  205.  *          stem:  directory stem is returned
  206.  * Returns: successful or not
  207.  * Notes:   we need to validate the search directory.  we only let the
  208.  *            user enter a valid directory name -- there are too damn
  209.  *            many expections and special cases in unix.
  210.  *          if the user presses enter, lets assume he wants cwd.
  211.  */
  212. int  validate_path( char *dname, char *stem )
  213. {
  214. int  rc;
  215. int  len;
  216. int  i;
  217. char *p;
  218. char temp[PATH_MAX+2];  /* directory stem */
  219. struct stat fstat;
  220. DIR  *dp;               /* DIR is defined in <dirent.h> */
  221.  
  222.    rc = OK;
  223.    /*
  224.     * if path name is empty then the current working directory is implied.
  225.     */
  226.    if (dname[0] == '\0') {
  227.       if (getcwd( temp, PATH_MAX+2 ) != NULL) {
  228.  
  229.          /*
  230.           * copy current working directory into stem.
  231.           */
  232.          strcpy( dname, temp );
  233.          strcpy( stem, dname );
  234.       } else
  235.          rc = ERROR;
  236.    }
  237.  
  238.    if (rc == OK) {
  239.  
  240.       /*
  241.        * get the attributes of the search pattern.  unlike DOS where we
  242.        *   can do file patterns, ie. *.c, lets only do directories in unix.
  243.        * the functions below are POSIX, i think...
  244.        */
  245.       if (stat( dname, &fstat ) >= 0) {
  246.          if (!S_ISDIR( fstat.st_mode ))
  247.             rc = ERROR;
  248.          else
  249.             strcpy( stem, dname );
  250.       }
  251. #if defined( __TDE_JUNK__ )
  252.        else {
  253.  
  254.          /*
  255.           * OK.  now let's try to do a UNIX file pattern, i.e. *.c
  256.           */
  257.          if ((dp = opendir( dname )) == NULL) {
  258.  
  259.             /*
  260.              * if user entered something like *.c, UNIX returns an ERROR.
  261.              * now, let's get the FULL path and try it again.
  262.              */
  263.             if (getcwd( temp, PATH_MAX+2 ) != NULL) {
  264.                len = strlen( temp );
  265.                if (temp[len-1] != '/')
  266.                   strcat( temp, "/" );
  267.                strcat( temp, dname );
  268.  
  269.                if ((dp = opendir( temp )) == NULL)
  270.                   rc = ERROR;
  271.                else {
  272.                   strcpy( dname, temp );
  273.                   closedir( dp );
  274.                }
  275.             } else
  276.                rc = ERROR;
  277.          } else
  278.             closedir( dp );
  279.  
  280.  
  281.          if (rc == OK) {
  282.             strcpy( temp, dname );
  283.             len = strlen( dname );
  284.             for (i=len,p=temp+len; i>=0; i--) {
  285.                /*
  286.                 *  if we run into the '/' then we got a stem.
  287.                 */
  288.                if (*p == '/') {
  289.                   p = temp + i;
  290.                   *(p+1) = '\0';
  291.                   break;
  292.                /*
  293.                 * if we're at the beginning of the string, stem == '\0'
  294.                 */
  295.                } else if (i == 0) {
  296.                   strcpy( temp, "/" );
  297.                   break;
  298.                }
  299.                --p;
  300.             }
  301.             strcpy( stem, temp );
  302.          }
  303.       }
  304. #endif
  305.    }
  306.  
  307.    if (rc == OK) {
  308.       /*
  309.        * if this is the root directory ( / ), don't append '/' to it.
  310.        */
  311.       len = strlen( stem );
  312.       if (stem[len-1] != '/')
  313.          strcat( stem, "/" );
  314.    }
  315.    return( rc );
  316. }
  317.  
  318.  
  319. /*
  320.  * Name:    list_and_pick
  321.  * Purpose: To show matching file names and let user pick a file
  322.  * Date:    November 13, 1993
  323.  * Passed:  dname:  directory search pattern
  324.  *          stem:   stem of directory search pattern (directory name with '/')
  325.  *          window:  pointer to current window
  326.  * Returns: return code from pick.  rc = OK, then edit a new file.
  327.  * Notes:   real work routine of this function.  save the cwd and let the
  328.  *           user search upwards or downwards thru the directory structure.
  329.  */
  330. int  list_and_pick( char *dname, char *stem, TDE_WIN *window )
  331. {
  332. int  rc;
  333. UNIX_DTA unix_dta;      /* our unix dta */
  334. DIR  *dp;               /* DIR is defined in <dirent.h> */
  335. struct stat fstat;      /* stat buffer */
  336. DIRECTORY dir;          /* contains all info for dir display */
  337. unsigned int cnt;       /* number of matching files */
  338. FTYPE *flist, *p;       /* pointer to list of matching files */
  339. char cwd[PATH_MAX+2];   /* save the current working directory in this buff */
  340. char dbuff[PATH_MAX+2]; /* temporary directory buff */
  341. char prefix[PATH_MAX+2];/* directory prefix  */
  342. char *eos;              /* end of stem pointer */
  343. int  change_directory = FALSE;
  344. int  stop;
  345. int  len;
  346. int  prompt_line;
  347.  
  348.    /*
  349.     * who knows the directory structure for unix systems???  it varies from
  350.     *  release to release and from port to port.  use POSIX functions, which
  351.     *  also change from release to release (IEEE 1003.1 vs IEEE 1003.1a),
  352.     *  to get directory elements.
  353.     */
  354.    rc = OK;
  355.    if ((dp = opendir( dname )) == NULL) {
  356.       rc = ERROR;
  357.       flist = NULL;
  358.    } else {
  359.  
  360.       /*
  361.        * eos == end of stem
  362.        */
  363.       strcpy( prefix, stem );
  364.       eos = prefix + strlen( prefix );
  365.  
  366.       for (cnt=1; my_findnext( dp, &unix_dta ) == OK;) {
  367.          strcpy( eos, unix_dta.fname );
  368.          if (stat( eos, &fstat ) >= 0) {
  369.             if (S_ISREG( fstat.st_mode ) || S_ISDIR( fstat.st_mode ))
  370.                ++cnt;
  371.          }
  372.       }
  373.       closedir( dp );
  374.       flist = (FTYPE *)calloc( cnt, sizeof(FTYPE) );
  375.    }
  376.  
  377.  
  378.    if (rc != ERROR && flist != NULL) {
  379.  
  380.       prompt_line = g_display.nlines;
  381.       stop = FALSE;
  382.       if (getcwd( cwd, PATH_MAX+2 ) == NULL) {
  383.          stop = TRUE;
  384.          rc = ERROR;
  385.       }
  386.  
  387.       while (stop == FALSE) {
  388.          /*
  389.           * If we had enough memory, find all matching file names.  Append
  390.           *  '/' to the end of subdirectory names so user will know if
  391.           *  name is a directory.  Might as well find everything, because
  392.           *  i also forget subdirectory names, too.
  393.           *
  394.           * when we get here, we have already done: 1) my_findfirst and
  395.           *  my_findnext, 2) counted the number of matching files, and
  396.           *  3) allocated space.
  397.           */
  398.          p = flist;
  399.          cnt = 0;
  400.  
  401.          if ((dp = opendir( dname )) == NULL)
  402.             rc = ERROR;
  403.          if (rc != ERROR) {
  404.  
  405.             /*
  406.              * p is pointer that walks down the file info structure.
  407.              *  save the file name, file size, and directory character,
  408.              *  if needed, for each matching file we find.
  409.              */
  410.  
  411.             /*
  412.              * eos == end of stem
  413.              */
  414.             strcpy( prefix, stem );
  415.             eos = prefix + strlen( prefix );
  416.  
  417.             for (cnt=0; my_findnext( dp, &unix_dta ) == OK;) {
  418.  
  419.                assert( strlen( unix_dta.fname ) < NAME_MAX + 2 );
  420.  
  421.                strcpy( eos, unix_dta.fname );
  422.                if (stat( eos, &fstat ) >= 0) {
  423.                   if (S_ISREG( fstat.st_mode ) || S_ISDIR( fstat.st_mode )) {
  424.                      strcpy( p->fname, unix_dta.fname );
  425.                      p->fsize = fstat.st_size;
  426.                      p->access = OK;
  427.                      if (S_ISDIR( fstat.st_mode )) {
  428.                         strcat( p->fname, "/" );
  429.  
  430.                         /*
  431.                          * test for permission
  432.                          */
  433.                         if (access( prefix, X_OK | R_OK ) < 0 )
  434.                            p->access = ERROR;
  435.                      }
  436.                      ++cnt;
  437.                      ++p;
  438.                   }
  439.                }
  440.             }
  441.             closedir( dp );
  442.          }
  443.  
  444.          if (rc != ERROR) {
  445.             shell_sort( flist, cnt );
  446.  
  447.             /*
  448.              * figure out number of rows, cols, etc... then display dir list
  449.              */
  450.             setup_directory_window( &dir, cnt );
  451.             write_directory_list( flist, dir );
  452.  
  453.             /*
  454.              * Let user select file name or another search directory.
  455.              *  Save the choice in dbuff.  rc == OK if user selected file or dir.
  456.              */
  457.             rc = select_file( flist, stem, &dir );
  458.  
  459.             assert( strlen( flist[dir.select].fname ) < NAME_MAX );
  460.  
  461.             strcpy( dbuff, flist[dir.select].fname );
  462.          }
  463.  
  464.          /*
  465.           *  give memory back.
  466.           */
  467.          free( flist );
  468.          flist = NULL;
  469.  
  470.          if (rc == ERROR)
  471.             stop = TRUE;
  472.          else {
  473.             len = strlen( dbuff );
  474.  
  475.             /* check this */
  476.  
  477.             /*
  478.              * If the last character in a file name is '/' then let's
  479.              *  do a dir on selected directory.  See the matching
  480.              *  else when the user selects a file.
  481.              */
  482.             if (dbuff[len-1] == '/') {
  483.  
  484.                /*
  485.                 * Stem has subdirectory path.  dbuff has selected path.
  486.                 * Create a new dname with stem and dbuff.
  487.                 */
  488.  
  489.                assert( strlen( stem ) + strlen( dbuff ) < PATH_MAX );
  490.  
  491.                strcpy( dname, stem );
  492.                strcat( dname, dbuff );
  493.                len = strlen( dname );
  494.                strcpy( dbuff, dname );
  495.  
  496.                /*
  497.                 * The last character in dbuff is '/', because we append the
  498.                 *  '/' to every directory entry in the file list.  Replace
  499.                 *  it with a NULL char then we will have a valid path name.
  500.                 */
  501.                dbuff[len-1] = '\0';
  502.  
  503.                /*
  504.                 * now let's change to the selected subdirectory.
  505.                 */
  506.                rc = set_current_directory( dbuff );
  507.                if (rc == OK) {
  508.  
  509.                   /*
  510.                    * Every time we change directories, we need to get the
  511.                    *  current directory so we will be sure to have the
  512.                    *  correct path.
  513.                    */
  514.                   rc = get_current_directory( dbuff, PATH_MAX + 2 );
  515.                   if (rc == OK) {
  516.  
  517.                      assert( strlen( dbuff ) < PATH_MAX );
  518.  
  519.                      strcpy( dname, dbuff );
  520.                      change_directory = TRUE;
  521.                   }
  522.                }
  523.  
  524.                /*
  525.                 * Validate the new path and allocate memory for the
  526.                 *  matching files.
  527.                 */
  528.                if (rc == OK)
  529.                   rc = validate_path( dname, stem );
  530.                if (rc == OK) {
  531.  
  532.                   if ((dp = opendir( dname )) == NULL) {
  533.                      rc = ERROR;
  534.                      flist = NULL;
  535.                   } else {
  536.  
  537.                      /*
  538.                       * eos == end of stem.  here, we just count the
  539.                       *  number of files and subdirectories and allocate
  540.                       *  enough memory for the flist.
  541.                       */
  542.                      strcpy( prefix, stem );
  543.                      eos = prefix + strlen( prefix );
  544.                      for (cnt=1; my_findnext( dp, &unix_dta ) == OK;) {
  545.                         strcpy( eos, unix_dta.fname );
  546.                         if (stat( eos, &fstat ) >= 0) {
  547.                            if (S_ISREG( fstat.st_mode ) || S_ISDIR( fstat.st_mode ))
  548.                               ++cnt;
  549.                         }
  550.                      }
  551.                      closedir( dp );
  552.                      flist = (FTYPE *)calloc( cnt, sizeof(FTYPE) );
  553.                   }
  554.                }
  555.                if (flist == NULL || rc == ERROR) {
  556.                   stop = TRUE;
  557.                   rc = ERROR;
  558.                   if (flist != NULL) {
  559.                      free( flist );
  560.                      flist = NULL;
  561.                   }
  562.                }
  563.             } else {
  564.  
  565.                /*
  566.                 * user selected a file.  store complete path in dname and
  567.                 *  file name in stem.
  568.                 */
  569.                rc = OK;
  570.                stop = TRUE;
  571.  
  572.                assert( strlen( stem ) + strlen( dbuff ) < PATH_MAX );
  573.  
  574.                strcpy( dname, stem );
  575.                strcat( dname, dbuff );
  576.                strcpy( stem, dbuff );
  577.             }
  578.          }
  579.       }
  580.  
  581.       /*
  582.        * Go back to the current directory if needed.
  583.        */
  584.       if (change_directory)
  585.          set_current_directory( cwd );
  586.       if (window != NULL)
  587.          redraw_screen( window );
  588.    } else {
  589.       /*
  590.        * out of memory
  591.        */
  592.       error( WARNING,  window != NULL ? window->bottom_line : g_display.nlines,
  593.              dir3 );
  594.       rc = ERROR;
  595.    }
  596.    return( rc );
  597. }
  598.  
  599.  
  600. /*
  601.  * Name:     setup_directory_window
  602.  * Purpose:  set number of rows and cols in directory window
  603.  * Date:     November 13, 1993
  604.  * Modified: November 13, 1993, Frank Davis per Byrial Jensen
  605.  * Passed:   dir: pointer to directory structure
  606.  *           cnt: number of files
  607.  * Notes:    set up stuff we need to know about how to display files.
  608.  */
  609. void setup_directory_window( DIRECTORY *dir, int cnt )
  610. {
  611. int  i;
  612. int  wid;
  613. char temp[MAX_COLS];    /* line to output */
  614.  
  615.    /*
  616.     * setup the fixed vars used in dir display.
  617.     *    dir->col =      physical upper left column of dir screen
  618.     *    dir->row =      physical upper left row or line of dir screen
  619.     *    dir->wid =      width of physical screen
  620.     *    dir->hgt =      height of physical screen
  621.     *    dir->max_cols   number of columns of files in dir screen
  622.     *    dir->max_lines  number of lines of files in each column in dir screen
  623.     *    dir->cnt        number of files in list
  624.     */
  625.    dir->col = 3;
  626.    dir->row = 5;
  627.    wid = dir->wid = 72;
  628.    dir->hgt = 16;
  629.    dir->max_cols = 4;
  630.    dir->max_lines = 10;
  631.    dir->cnt = cnt;
  632.  
  633.    /*
  634.     * Find out how many lines in each column are needed to display
  635.     *  matching files.
  636.     */
  637.    dir->lines = dir->cnt / dir->max_cols + (dir->cnt % dir->max_cols ? 1 : 0);
  638.    if (dir->lines > dir->max_lines)
  639.       dir->lines = dir->max_lines;
  640.  
  641.    /*
  642.     * Find out how many columns of file names we need.
  643.     */
  644.    dir->cols = dir->cnt / dir->lines + (dir->cnt % dir->lines ? 1 : 0);
  645.    if (dir->cols > dir->max_cols)
  646.       dir->cols = dir->max_cols;
  647.  
  648.  
  649.    /*
  650.     * Find the maximun number of file names we can display in help screen.
  651.     */
  652.    dir->avail = dir->lines * dir->cols;
  653.  
  654.    /*
  655.     * Now find the number of file names we do have on the screen.  Every
  656.     *  time we slide the "window", we have to calculate a new nfiles.
  657.     */
  658.    dir->nfiles = dir->cnt > dir->avail ? dir->avail : dir->cnt;
  659.  
  660.    /*
  661.     * A lot of times, the number of matching files will not fit evenly
  662.     *  in our help screen.  The last column on the right will be partially
  663.     *  filled, hence the variable name prow (partial row).  When there are
  664.     *  more file names than can fit on the screen, we have to calculate
  665.     *  prow every time we slide the "window" of files.
  666.     */
  667.    dir->prow = dir->lines - (dir->avail - dir->nfiles);
  668.  
  669.    /*
  670.     * Find out how many "virtual" columns of file names we have.  If
  671.     *  all the files can fit in the dir screen, there will be no
  672.     *  virtual columns.
  673.     */
  674.    if (dir->cnt < dir->avail)
  675.       dir->vcols = 0;
  676.    else
  677.       dir->vcols =  (dir->cnt - dir->avail) / dir->max_lines +
  678.                    ((dir->cnt - dir->avail) % dir->max_lines ? 1 : 0);
  679.  
  680.    /*
  681.     * Find the physical display column in dir screen.
  682.     */
  683.    dir->flist_col[0] = dir->col + 2;
  684.    for (i=1; i<dir->max_cols; i++)
  685.       dir->flist_col[i] = dir->flist_col[i-1] + 17;
  686.  
  687.    /*
  688.     * Now, draw the borders of the dir screen.
  689.     */
  690.    for (i=0; i < dir->hgt; i++) {
  691.       if (i == 0 || i == dir->hgt-1) {
  692.          memset( temp, HORIZONTAL_LINE, wid );
  693.          temp[wid] = '\0';
  694.          if (i == 0) {
  695.             temp[0] = CORNER_LEFT_UP;
  696.             temp[wid-1] = CORNER_RIGHT_UP;
  697.          } else {
  698.             temp[0] = CORNER_LEFT_DOWN;
  699.             temp[wid-1] = CORNER_RIGHT_DOWN;
  700.          }
  701.       } else {
  702.          memset( temp, ' ', wid );
  703.          temp[wid] = '\0';
  704.          temp[0] = temp[wid-1] = VERTICAL_LINE;
  705.       }
  706.       s_output( temp, dir->row+i, dir->col, g_display.help_color );
  707.    }
  708.  
  709.    /*
  710.     * Write headings in help screen.
  711.     */
  712.    s_output( dir1, dir->row+DIR1_ROW, dir->col+DIR1_COL, g_display.help_color );
  713.    s_output( dir4, dir->row+DIR4_ROW, dir->col+DIR4_COL, g_display.help_color );
  714.    s_output( dir5, dir->row+DIR5_ROW, dir->col+DIR5_COL, g_display.help_color );
  715.    s_output( dir6, dir->row+DIR6_ROW, dir->col+DIR6_COL, g_display.help_color );
  716.    s_output( dir7, dir->row+DIR7_ROW, dir->col+DIR7_COL, g_display.help_color );
  717. }
  718.  
  719.  
  720. /*
  721.  * Name:    write_directory_list
  722.  * Purpose: given directory list, display matching files
  723.  * Date:    November 13, 1993
  724.  * Passed:  flist: pointer to list of files
  725.  *          dir:   directory display structure
  726.  * Notes:   blank out the previous file name and display the new one.
  727.  */
  728. void write_directory_list( FTYPE *flist, DIRECTORY dir )
  729. {
  730. FTYPE *p, *top;
  731. int  i;
  732. int  j;
  733. int  k;
  734. int  end;
  735. int  line;
  736. int  col;
  737. int  color;
  738. char temp[NAME_MAX+2];
  739. char blank[20];         /* blank out file names */
  740.  
  741.    memset( blank, ' ', 15 );
  742.    blank[15] = '\0';
  743.    color = g_display.help_color;
  744.    top = flist;
  745.    for (i=0; i < dir.lines; ++i) {
  746.       p = top;
  747.       end = FALSE;
  748.       for (j=0; j < dir.cols; ++j) {
  749.          col = dir.flist_col[j];
  750.          line = i + dir.row + 5;
  751.  
  752.          /*
  753.           * We need to blank out all lines and columns used to display
  754.           *  files, because there may be some residue from a previous dir
  755.           */
  756.          s_output( blank, line, col, color );
  757.          if (!end) {
  758.             if (strlen( p->fname ) <= 15)
  759.                s_output( p->fname, line, col, color );
  760.             else {
  761.  
  762.                assert( strlen( p->fname ) < NAME_MAX + 1 );
  763.  
  764.                strcpy( temp, p->fname );
  765.                temp[15] = '\0';
  766.                s_output( temp, line, col, color );
  767.             }
  768.             p += dir.lines;
  769.             k = p - flist;
  770.             if (k >= dir.nfiles)
  771.                end = TRUE;
  772.          }
  773.       }
  774.       ++top;
  775.    }
  776. }
  777.  
  778.  
  779. /*
  780.  * Name:     select_file
  781.  * Purpose:  To let user select a file from dir list
  782.  * Date:     November 13, 1993
  783.  * Modified: November 13, 1993, Frank Davis per Byrial Jensen
  784.  * Passed:   flist: pointer to list of files
  785.  *           stem:  base directory
  786.  *           dir:   directory display stuff
  787.  * Notes:    let user move thru the file names with the cursor keys
  788.  */
  789. int  select_file( FTYPE *flist, char *stem, DIRECTORY *dir )
  790. {
  791. int  ch;                /* input character from user */
  792. int  func;              /* function of character input by user */
  793. int  fno;               /* index into flist of the file under cursor */
  794. int  goodkey;           /* is key a recognized function key? */
  795. int  r;                 /* current row of cursor */
  796. int  c;                 /* current column of cursor */
  797. int  offset;            /* offset into file list */
  798. int  stop;              /* stop indicator */
  799. int  color;             /* color of help screen */
  800. int  file_color;        /* color of current file */
  801. int  change;            /* boolean, hilite another file? */
  802. int  oldr;              /* old row */
  803. int  oldc;              /* old column */
  804. char asize[20];         /* ascii file size */
  805. char blank[NAME_MAX];   /* blank out file names */
  806. char temp[PATH_MAX];
  807.  
  808.    /*
  809.     * initial everything.
  810.     */
  811.    memset( blank, ' ', 15 );
  812.    blank[15] = '\0';
  813.    c = r = 1;
  814.    ch = fno = offset = 0;
  815.    color = g_display.help_color;
  816.    file_color = g_display.hilited_file;
  817.    goodkey = TRUE;
  818.    stop = FALSE;
  819.  
  820.    /*
  821.     * UNIX directory names can get quite long.  lets only show the first 50.
  822.     */
  823.    if (strlen( stem ) < 50)
  824.       s_output( stem, dir->row+DIR1_ROW, dir->col+strlen( dir1 )+3, color );
  825.    else {
  826.       strcpy( temp, stem );
  827.       temp[50] = '\0';
  828.       s_output( temp, dir->row+DIR1_ROW, dir->col+strlen( dir1 )+3, color );
  829.    }
  830.  
  831.    if (strlen( flist[fno].fname ) < 50 )
  832.       s_output( flist[fno].fname, dir->row+DIR4_ROW,
  833.                 dir->col+strlen( dir4 )+3, color );
  834.    else {
  835.       strcpy( temp, flist[fno].fname );
  836.       temp[50] = '\0';
  837.       s_output( temp, dir->row+DIR4_ROW, dir->col+strlen( dir4 )+3, color );
  838.    }
  839.    my_ltoa( flist[fno].fsize, asize, 10 );
  840.    s_output( blank, dir->row+DIR5_ROW, dir->col+strlen( dir5 )+3, color );
  841.    s_output( asize, dir->row+DIR5_ROW, dir->col+strlen( dir5 )+3, color );
  842.    my_ltoa( dir->cnt,  asize, 10 );
  843.    s_output( blank, dir->row+DIR6_ROW, dir->col+DIR6_COL+strlen( dir6 ), color);
  844.    s_output( asize, dir->row+DIR6_ROW, dir->col+DIR6_COL+strlen( dir6 ), color);
  845.    xygoto( (c-1)*17+dir->col+2, r+dir->row+4 );
  846.    hlight_line( (c-1)*17+dir->col+2, r+dir->row+4, 15, file_color );
  847.  
  848.    refresh( );
  849.  
  850.    change = FALSE;
  851.    func = AbortCommand;
  852.    while (stop == FALSE) {
  853.       oldr = r;
  854.       oldc = c;
  855.       ch = getkey( );
  856.       func = getfunc( ch );
  857.  
  858.       /*
  859.        * User may have redefined the Enter and ESC keys.  Make the Enter key
  860.        *  perform a Rturn in this function. Make the ESC key do an AbortCommand.
  861.        */
  862.       if (ch == RTURN)
  863.          func = Rturn;
  864.       else if (ch == ESC)
  865.          func = AbortCommand;
  866.  
  867.       switch (func) {
  868.          case Rturn       :
  869.          case NextLine    :
  870.          case BegNextLine :
  871.             if (flist[fno].access == ERROR) {
  872.                error( WARNING, g_display.nlines, dir8 );
  873.                xygoto( (c-1)*17+dir->col+2+15, r+dir->row+4 );
  874.             } else
  875.                stop = TRUE;
  876.             break;
  877.          case AbortCommand :
  878.             stop = TRUE;
  879.             break;
  880.          case LineUp :
  881.             if (r > 1) {
  882.                change = TRUE;
  883.                --r;
  884.             } else {
  885.                r = dir->lines;
  886.                change = TRUE;
  887.                if (offset == 0 || c > 1) {
  888.                   if (c > 1)
  889.                      --c;
  890.                } else if (dir->vcols > 0 && offset > 0 && c == 1) {
  891.                   /*
  892.                    * recalculate the dir display stuff.
  893.                    */
  894.                   offset -= dir->lines;
  895.                   recalculate_dir( dir, flist, offset );
  896.                }
  897.             }
  898.             goodkey = TRUE;
  899.             break;
  900.          case LineDown :
  901.             if (r < dir->prow) {
  902.                change = TRUE;
  903.                ++r;
  904.             } else if (r < dir->lines && c != dir->cols) {
  905.                change = TRUE;
  906.                ++r;
  907.             } else {
  908.                change = TRUE;
  909.                r = 1;
  910.                if (offset == dir->vcols * dir->lines || c < dir->cols) {
  911.                   if (c < dir->cols)
  912.                      ++c;
  913.                } else if (dir->vcols > 0 && offset < dir->vcols * dir->lines &&
  914.                          c == dir->cols) {
  915.                   offset += dir->lines;
  916.                   recalculate_dir( dir, flist, offset );
  917.                }
  918.             }
  919.             goodkey = TRUE;
  920.             break;
  921.          case CharLeft :
  922.             if (offset == 0 || c > 1) {
  923.                if (c > 1) {
  924.                   change = TRUE;
  925.                   --c;
  926.                }
  927.             } else if (dir->vcols > 0 && offset > 0 && c == 1) {
  928.                change = TRUE;
  929.  
  930.                /*
  931.                 * recalculate the dir display stuff.
  932.                 */
  933.                offset -= dir->lines;
  934.                recalculate_dir( dir, flist, offset );
  935.             }
  936.             goodkey = TRUE;
  937.             break;
  938.          case CharRight :
  939.             if (offset == dir->vcols * dir->lines || c < dir->cols) {
  940.                if (c < dir->cols) {
  941.                   change = TRUE;
  942.                   ++c;
  943.                   if (c == dir->cols) {
  944.                      if ( r > dir->prow)
  945.                         r = dir->prow;
  946.                   }
  947.                }
  948.             } else if (dir->vcols > 0 && offset < dir->vcols * dir->lines &&
  949.                          c == dir->cols) {
  950.                change = TRUE;
  951.                offset += dir->lines;
  952.                recalculate_dir( dir, flist, offset );
  953.                if (r > dir->prow)
  954.                   r = dir->prow;
  955.             }
  956.             goodkey = TRUE;
  957.             break;
  958.          case BegOfLine :
  959.             change = TRUE;
  960.             c = r = 1;
  961.             goodkey = TRUE;
  962.             break;
  963.          case EndOfLine :
  964.             change = TRUE;
  965.             r = dir->prow;
  966.             c = dir->cols;
  967.             goodkey = TRUE;
  968.             break;
  969.          case ScreenDown :
  970.             change = TRUE;
  971.             r = (c == dir->cols) ? r = dir->prow : dir->lines;
  972.             goodkey = TRUE;
  973.             break;
  974.          case ScreenUp :
  975.             change = TRUE;
  976.             r = 1;
  977.             goodkey = TRUE;
  978.             break;
  979.          default :
  980.             break;
  981.       }
  982.       if (goodkey) {
  983.          memset( temp, ' ', 50 );
  984.          temp[50] = '\0';
  985.          s_output( temp, dir->row+DIR4_ROW, dir->col+strlen( dir4 )+3, color );
  986.          fno = offset + (c-1)*dir->lines + (r-1);
  987.          if (strlen( flist[fno].fname ) < 50)
  988.             s_output( flist[fno].fname, dir->row+DIR4_ROW,
  989.                          dir->col+strlen( dir4 )+3, color );
  990.          else {
  991.             strcpy( temp, flist[fno].fname );
  992.             temp[50] = '\0';
  993.             s_output( temp, dir->row+DIR4_ROW, dir->col+strlen( dir4 )+3,color);
  994.          }
  995.          my_ltoa( flist[fno].fsize, asize, 10 );
  996.          s_output( blank, dir->row+DIR5_ROW, dir->col+strlen( dir5 )+3, color );
  997.          s_output( asize, dir->row+DIR5_ROW, dir->col+strlen( dir5 )+3, color );
  998.  
  999.          xygoto( (c-1)*17+dir->col+2, r+dir->row+4 );
  1000.          goodkey = FALSE;
  1001.          if (change) {
  1002.             hlight_line( (oldc-1)*17+dir->col+2, oldr+dir->row+4, 15, color );
  1003.             hlight_line( (c-1)*17+dir->col+2, r+dir->row+4, 15, file_color );
  1004.             change = FALSE;
  1005.          }
  1006.       }
  1007.       refresh( );
  1008.    }
  1009.    dir->select = fno;
  1010.    return( func == AbortCommand ? ERROR : OK );
  1011. }
  1012.  
  1013. #else
  1014. /*
  1015.  **********************************************************************
  1016.  ******************************  PART 2  ******************************
  1017.  **********************************************************************
  1018.  *
  1019.  * Calls to BIOS and writes to PC hardware.
  1020.  */
  1021.  
  1022. /*
  1023.  * Name:    dir_help
  1024.  * Purpose: To prompt the user and list the directory contents
  1025.  * Date:    February 13, 1992
  1026.  * Passed:  window:  pointer to current window
  1027.  */
  1028. int  dir_help( TDE_WIN *window )
  1029. {
  1030. char dname[MAX_COLS+2]; /* directory search pattern */
  1031. char stem[MAX_COLS+2];  /* directory stem */
  1032. char drive[_MAX_DRIVE]; /* splitpath drive buff */
  1033. char dir[_MAX_DIR];     /* splitpath dir buff */
  1034. char fname[_MAX_FNAME]; /* splitpath fname buff */
  1035. char ext[_MAX_EXT];     /* splitpath ext buff */
  1036. char display_buff[(MAX_COLS+2)*2];
  1037. int  rc;
  1038. int  file_mode;
  1039. int  bin_length;
  1040. int  prompt_line;
  1041.  
  1042.    if (window != NULL) {
  1043.       entab_linebuff( );
  1044.       if (un_copy_line( window->ll, window, TRUE ) == ERROR)
  1045.          return( ERROR );
  1046.       prompt_line = window->bottom_line;
  1047.    } else
  1048.       prompt_line = g_display.nlines;
  1049.  
  1050.    /*
  1051.     * search path or pattern
  1052.     */
  1053.    dname[0] = '\0';
  1054.    rc = get_name( dir1, prompt_line, dname, g_display.message_color );
  1055.  
  1056.    if (rc == OK) {
  1057.       if (validate_path( dname, stem ) == OK) {
  1058.          rc = list_and_pick( dname, stem, window );
  1059.  
  1060.          /*
  1061.           * if everything is everything, load in the file selected by user.
  1062.           */
  1063.          if (rc == OK) {
  1064.             file_mode = TEXT;
  1065.             bin_length = 0;
  1066.             _splitpath( dname, drive, dir, fname, ext );
  1067.             if (stricmp( ext, ".exe" ) == 0  ||  stricmp( ext, ".com" ) == 0) {
  1068.                file_mode = BINARY;
  1069.                bin_length = g_status.file_chunk;
  1070.             } else if (g_status.file_mode == BINARY) {
  1071.                save_screen_line( 0, prompt_line, display_buff );
  1072.                /*
  1073.                 * open file in BINARY mode (y/n)
  1074.                 */
  1075.                set_prompt( ed18, prompt_line );
  1076.                if (get_yn( ) == A_YES) {
  1077.                   file_mode = BINARY;
  1078.                   bin_length = g_status.file_chunk;
  1079.                }
  1080.                restore_screen_line( 0, prompt_line, display_buff );
  1081.             }
  1082.             if (window != NULL)
  1083.                attempt_edit_display( dname, LOCAL, file_mode, bin_length );
  1084.             else
  1085.                attempt_edit_display( dname, GLOBAL, file_mode, bin_length );
  1086.          }
  1087.       } else {
  1088.          /*
  1089.           * invalid path or file name
  1090.           */
  1091.          error( WARNING,
  1092.                 window != NULL ? window->bottom_line : g_display.nlines, dir2 );
  1093.          rc = ERROR;
  1094.       }
  1095.    }
  1096.    return( rc );
  1097. }
  1098.  
  1099.  
  1100. /*
  1101.  * Name:    dir_help_name
  1102.  * Purpose: To display name of directory
  1103.  * Date:    February 13, 1992
  1104.  * Passed:  window:  pointer to current window
  1105.  */
  1106. int  dir_help_name( TDE_WIN *window, char *name )
  1107. {
  1108. char dname[MAX_COLS+2]; /* directory search pattern */
  1109. char stem[MAX_COLS+2];  /* directory stem */
  1110. char drive[_MAX_DRIVE]; /* splitpath drive buff */
  1111. char dir[_MAX_DIR];     /* splitpath dir buff */
  1112. char fname[_MAX_FNAME]; /* splitpath fname buff */
  1113. char ext[_MAX_EXT];     /* splitpath ext buff */
  1114. int  rc;
  1115. int  file_mode;
  1116. int  bin_length;
  1117. int  prompt_line;
  1118.  
  1119.    rc = OK;
  1120.    if (window != NULL) {
  1121.       entab_linebuff( );
  1122.       if (un_copy_line( window->ll, window, TRUE ) == ERROR)
  1123.          return( ERROR );
  1124.       prompt_line = window->bottom_line;
  1125.    } else
  1126.       prompt_line = g_display.nlines;
  1127.  
  1128.    /*
  1129.     * search path or pattern
  1130.     */
  1131.  
  1132.    strcpy( dname, name );
  1133.    if (rc == OK) {
  1134.       if ((rc = validate_path( dname, stem )) == OK) {
  1135.          rc = list_and_pick( dname, stem, window );
  1136.  
  1137.          /*
  1138.           * if everything is everything, load in the file selected by user.
  1139.           */
  1140.          if (rc == OK) {
  1141.             file_mode = TEXT;
  1142.             bin_length = 0;
  1143.             _splitpath( dname, drive, dir, fname, ext );
  1144.             if (stricmp( ext, ".exe" ) == 0  ||  stricmp( ext, ".com" ) == 0) {
  1145.                file_mode = BINARY;
  1146.                bin_length = g_status.file_chunk;
  1147.             }
  1148.             if (window != NULL)
  1149.                attempt_edit_display( dname, LOCAL, file_mode, bin_length );
  1150.             else
  1151.                attempt_edit_display( dname, GLOBAL, file_mode, bin_length );
  1152.          }
  1153.       } else
  1154.          /*
  1155.           * invalid path or file name
  1156.           */
  1157.          error( WARNING,
  1158.                 window != NULL ? window->bottom_line : g_display.nlines, dir2 );
  1159.    }
  1160.    return( rc );
  1161. }
  1162.  
  1163.  
  1164. /*
  1165.  * Name:    validate_path
  1166.  * Purpose: make sure we got a valid search pattern or subdirectory
  1167.  * Date:    February 13, 1992
  1168.  * Passed:  dname: search path entered by user
  1169.  *          stem:  directory stem is returned
  1170.  * Returns: successful or not
  1171.  * Notes:   we need to validate the search path or pattern.  if the search
  1172.  *            pattern is valid, then we need to get the search stem.
  1173.  *          the user may enter a subdirectory or some kind of search pattern.
  1174.  *             if the user enters a subdirectory, then there are a few things
  1175.  *             we need to take care of  1) find out if the subdirectory is
  1176.  *             the root, 2) append a '\' to the subdirectory so we can create
  1177.  *             a search pattern for the subdirectory, 3) don't append '\' to
  1178.  *             the root, it already has a '\'.
  1179.  *          if the user enters a search pattern, then we need to dissect the
  1180.  *             search path.  we must create a stem from the search pattern.
  1181.  */
  1182. int  validate_path( char *dname, char *stem )
  1183. {
  1184. int  rc;
  1185. DTA  dta;               /* temp disk transfer struct for findfirst, etc. */
  1186. int  fattr;
  1187. int  i;
  1188. int  len;
  1189. char *p;
  1190. char temp[MAX_COLS+2];  /* directory stem */
  1191.  
  1192.    /*
  1193.     * if path name is void then the current working directory is implied.
  1194.     */
  1195.    if (dname[0] == '\0') {
  1196.  
  1197.       assert( strlen( stardotstar ) < MAX_COLS );
  1198.  
  1199.       strcpy( dname, stardotstar );
  1200.       stem[0] = '\0';
  1201.       rc = OK;
  1202.    } else {
  1203.  
  1204.       /*
  1205.        * get the attributes of the search pattern, so we can determine if
  1206.        * this is a pattern or subdirectory.
  1207.        */
  1208.       rc = get_fattr( dname, &fattr );
  1209.  
  1210.       if (rc == OK && (fattr & SUBDIRECTORY)) {
  1211.          assert( strlen( dname ) < MAX_COLS );
  1212.          strcpy( stem, dname );
  1213.  
  1214.          /*
  1215.           * if this is the root directory ( \ ), don't append '\' to it.
  1216.           * user entered a subdirectory - append *.* to get contents of
  1217.           * subdirectory.
  1218.           */
  1219.          len = strlen( stem );
  1220.          if (stem[len-1] != '\\') {
  1221.             strcat( stem, "\\" );
  1222.             strcat( dname, "\\" );
  1223.          }
  1224.          strcat( dname, stardotstar );
  1225.  
  1226.       /*
  1227.        * not a subdirectory.  let's see if any files match the search
  1228.        * pattern.
  1229.        */
  1230.       } else if (rc != ERROR) {
  1231.          if ((rc = my_findfirst( &dta, dname, NORMAL | READ_ONLY | HIDDEN |
  1232.                               SYSTEM | SUBDIRECTORY | ARCHIVE )) == OK) {
  1233.  
  1234.             /*
  1235.              * copy dname to "temp" so we can use "temp" to find the stem.
  1236.              *    we need to search the pattern backwards to figure the stem.
  1237.              */
  1238.  
  1239.             assert( strlen( dname ) < MAX_COLS );
  1240.  
  1241.             strcpy( temp, dname );
  1242.             len = strlen( dname );
  1243.             for (i=len,p=temp+len; i>=0; i--) {
  1244.                /*
  1245.                 *  if we run into the '\' or the ':', then we got a stem.
  1246.                 */
  1247.                if (*p == '\\' || *p == ':') {
  1248.                   p = temp + i;
  1249.                   *(p+1) = '\0';
  1250.                   break;
  1251.                /*
  1252.                 * if we're at the beginning of the string, stem == '\0'
  1253.                 */
  1254.                } else if (i == 0) {
  1255.                   *p = '\0';
  1256.                   break;
  1257.                }
  1258.                --p;
  1259.             }
  1260.  
  1261.             assert( strlen( temp ) < MAX_COLS );
  1262.  
  1263.             strcpy( stem, temp );
  1264.          } else
  1265.             rc = ERROR;
  1266.  
  1267.       /*
  1268.        * user did not enter a valid subdirectory name or search pattern.
  1269.        */
  1270.       } else
  1271.          rc = ERROR;
  1272.    }
  1273.    return( rc );
  1274. }
  1275.  
  1276.  
  1277. /*
  1278.  * Name:    list_and_pick
  1279.  * Purpose: To show matching file names and let user pick a file
  1280.  * Date:    February 13, 1992
  1281.  * Passed:  dname:  directory search pattern
  1282.  *          stem:   stem of directory search pattern
  1283.  *          window:  pointer to current window
  1284.  * Returns: return code from pick.  rc = OK, then edit a new file.
  1285.  * Notes:   real work routine of this function.  save the cwd and let the
  1286.  *           user search upwards or downwards thru the directory structure.
  1287.  *          since we are doing DOS directory functions, we need to check the
  1288.  *           return code after each DOS call for critical errors.
  1289.  */
  1290. int  list_and_pick( char *dname, char *stem, TDE_WIN *window )
  1291. {
  1292. int  rc;
  1293. DTA  dta;               /* disk transfer address for findfirst */
  1294. DIRECTORY dir;          /* contains all info for dir display */
  1295. unsigned int cnt;       /* number of matching files */
  1296. FTYPE *flist, *p;       /* pointer to list of matching files */
  1297. char cwd[MAX_COLS];     /* save the current working directory in this buff */
  1298. char dbuff[MAX_COLS];   /* temporary directory buff */
  1299. char prefix[MAX_COLS];  /* directory prefix  */
  1300. int  change_directory = FALSE;
  1301. int  stop;
  1302. int  len;
  1303. int  drive;
  1304.  
  1305.    /*
  1306.     * Some algorithms alloc the maximum possible number of files in
  1307.     *  a directory, eg. 256 or 512.  Let's count the number of matching
  1308.     *  files so we know egxactly how much memory to request from calloc.
  1309.     *  Depending on the op system, disk media, disk format, or version of DOS,
  1310.     *  the max number of files may vary, anyway, also, additionally.
  1311.     *  (see the unix section above, where the number of files changes with
  1312.     *   each port of unix to new toasters.)
  1313.     */
  1314.    rc = my_findfirst( &dta, dname, NORMAL | READ_ONLY | HIDDEN | SYSTEM |
  1315.                                 SUBDIRECTORY | ARCHIVE );
  1316.    if (rc != ERROR) {
  1317.       for (cnt=1; (rc = my_findnext( &dta )) == OK;)
  1318.          ++cnt;
  1319.       flist = (FTYPE *)calloc( cnt, sizeof(FTYPE) );
  1320.    } else
  1321.       flist = NULL;
  1322.    if (rc != ERROR && flist != NULL) {
  1323.  
  1324.       stop = FALSE;
  1325.       /*
  1326.        * If user entered drive name in search pattern, find out the drive and
  1327.        *  directory stem.
  1328.        */
  1329.       if (stem[1] == ':') {
  1330.  
  1331.          /*
  1332.           * If the second character of the search pattern is a ':', the
  1333.           *  the first character of the pattern should be the drive.
  1334.           *  Convert drive to lower case and get a numerical representation.
  1335.           * CAVEAT:  In DOS v 2.x, there may be up to 63 logical drives.
  1336.           *   my algorithm may blow up if the number of logical drives
  1337.           *   is greater than 'Z'.
  1338.           * For DOS >= 3, the number of drives is limited to 26, I think.
  1339.           */
  1340.          drive = stem[0];
  1341.          if (drive < 'a')
  1342.             drive += 32;
  1343.          drive = drive - 'a' + 1;
  1344.          rc = get_current_directory( dbuff, drive );
  1345.          if (rc == ERROR)
  1346.             stop = TRUE;
  1347.          else {
  1348.  
  1349.             /*
  1350.              * Put drive letter, ':', and '\' in front of current directory.
  1351.              */
  1352.             prefix[0] = (char)(drive - 1 + 'a');
  1353.             prefix[1] = ':';
  1354.             prefix[2] = '\\';
  1355.             prefix[3] = '\0';
  1356.             assert( strlen( prefix ) + strlen( dbuff ) < MAX_COLS );
  1357.             strcpy( cwd, prefix );
  1358.             strcat( cwd, dbuff );
  1359.          }
  1360.  
  1361.       /*
  1362.        * else get current directory from default drive
  1363.        */
  1364.       } else {
  1365.  
  1366.          /*
  1367.           * 0 = default drive.
  1368.           */
  1369.          drive = 0;
  1370.          rc = get_current_directory( dbuff, drive );
  1371.          if (rc == ERROR)
  1372.             stop = TRUE;
  1373.          else {
  1374.  
  1375.             /*
  1376.              * Put a '\' in front of the current directory.
  1377.              */
  1378.             prefix[0] = '\\';
  1379.             prefix[1] = '\0';
  1380.  
  1381.             assert( strlen( prefix ) + strlen( dbuff ) < MAX_COLS );
  1382.  
  1383.             strcpy( cwd, prefix );
  1384.             strcat( cwd, dbuff );
  1385.          }
  1386.       }
  1387.  
  1388.       while (stop == FALSE) {
  1389.          /*
  1390.           * If we had enough memory, find all matching file names.  Append
  1391.           *  '\\' at the end of subdirectory names so user will know if
  1392.           *  name is a directory.  Might as well find everything, because
  1393.           *  i also forget subdirectory names, too.
  1394.           *
  1395.           * when we get here, we have already done: 1) my_findfirst and
  1396.           *  my_findnext, 2) counted the number of matching files, and
  1397.           *  3) allocated space.
  1398.           */
  1399.          p = flist;
  1400.          cnt = 0;
  1401.  
  1402.          rc = my_findfirst( &dta, dname, NORMAL | READ_ONLY | HIDDEN | SYSTEM |
  1403.                                  SUBDIRECTORY | ARCHIVE );
  1404.          if (rc != ERROR) {
  1405.  
  1406.             /*
  1407.              * p is pointer that walks down the file info structure.
  1408.              *  save the file name, file size, and directory character,
  1409.              *  if needed, for each matching file we find.
  1410.              */
  1411.  
  1412.             assert( strlen( dta.name ) < 14 );
  1413.  
  1414.             strcpy( p->fname, dta.name );
  1415.             p->fsize = dta.size;
  1416.             if (dta.attrib & SUBDIRECTORY)
  1417.                strcat( p->fname, "\\" );
  1418.             for (cnt=1; (rc = my_findnext( &dta )) == OK; ) {
  1419.                ++p;
  1420.  
  1421.                assert( strlen( dta.name ) < 14 );
  1422.  
  1423.                strcpy( p->fname, dta.name );
  1424.                p->fsize = dta.size;
  1425.                if (dta.attrib & SUBDIRECTORY)
  1426.                   strcat( p->fname, "\\" );
  1427.                cnt++;
  1428.             }
  1429.          }
  1430.  
  1431.          if (rc != ERROR) {
  1432.             shell_sort( flist, cnt );
  1433.  
  1434.             /*
  1435.              * figure out number of rows, cols, etc... then display dir list
  1436.              */
  1437.             setup_directory_window( &dir, cnt );
  1438.             write_directory_list( flist, dir );
  1439.  
  1440.             /*
  1441.              * Let user select file name or another search directory.
  1442.              *  Save the choice in dbuff.  rc == OK if user selected file or dir.
  1443.              */
  1444.             rc = select_file( flist, stem, &dir );
  1445.  
  1446.             assert( strlen( flist[dir.select].fname ) < MAX_COLS );
  1447.  
  1448.             strcpy( dbuff, flist[dir.select].fname );
  1449.          }
  1450.  
  1451.          /*
  1452.           *  give memory back.
  1453.           */
  1454.          free( flist );
  1455.          flist = NULL;
  1456.  
  1457.          if (rc == ERROR)
  1458.             stop = TRUE;
  1459.          else {
  1460.             len = strlen( dbuff );
  1461.  
  1462.             /*
  1463.              * If the last character in a file name is '\' then let's
  1464.              *  do a dir on selected directory.  See the matching
  1465.              *  else when the user selects a file.
  1466.              */
  1467.             if (dbuff[len-1] == '\\') {
  1468.  
  1469.                /*
  1470.                 * Stem has subdirectory path.  dbuff has selected path.
  1471.                 * Create a new dname with stem and dbuff.
  1472.                 */
  1473.  
  1474.                assert( strlen( stem ) + strlen( dbuff ) < MAX_COLS );
  1475.  
  1476.                strcpy( dname, stem );
  1477.                strcat( dname, dbuff );
  1478.                len = strlen( dname );
  1479.                strcpy( dbuff, dname );
  1480.  
  1481.                /*
  1482.                 * The last character in dbuff is '\', because we append the
  1483.                 *  '\' to every directory entry in the file list.  Replace
  1484.                 *  it with a NULL char then we will have a valid path name.
  1485.                 */
  1486.                dbuff[len-1] = '\0';
  1487.  
  1488.                /*
  1489.                 * now let's change to the selected subdirectory.
  1490.                 */
  1491.                rc = set_current_directory( dbuff );
  1492.                if (rc == OK) {
  1493.  
  1494.                   /*
  1495.                    * Every time we change directories, we need to get the
  1496.                    *  current directory so we will be sure to have the
  1497.                    *  correct path.
  1498.                    */
  1499.                   rc = get_current_directory( dbuff, drive );
  1500.                   if (rc == OK) {
  1501.  
  1502.                      assert( strlen( prefix ) + strlen( dbuff ) < MAX_COLS );
  1503.  
  1504.                      strcpy( dname, prefix );
  1505.                      strcat( dname, dbuff );
  1506.                      change_directory = TRUE;
  1507.                   }
  1508.                }
  1509.  
  1510.                /*
  1511.                 * Validate the new path and allocate memory for the
  1512.                 *  matching files.
  1513.                 */
  1514.                if (rc == OK)
  1515.                   rc = validate_path( dname, stem );
  1516.                if (rc == OK) {
  1517.                   rc = my_findfirst( &dta, dname, NORMAL | READ_ONLY | HIDDEN |
  1518.                                   SYSTEM | SUBDIRECTORY | ARCHIVE );
  1519.                   if (rc != ERROR) {
  1520.                      for (cnt=1; (rc = my_findnext( &dta )) == OK;)
  1521.                         ++cnt;
  1522.                      flist = (FTYPE *)calloc( cnt, sizeof(FTYPE) );
  1523.                   }
  1524.                }
  1525.                if (flist == NULL || rc == ERROR) {
  1526.                   stop = TRUE;
  1527.                   rc = ERROR;
  1528.                   if (flist != NULL) {
  1529.                      free( flist );
  1530.                      flist = NULL;
  1531.                   }
  1532.                }
  1533.             } else {
  1534.  
  1535.                /*
  1536.                 * user selected a file.  store fname in dname and return.
  1537.                 */
  1538.                rc = OK;
  1539.                stop = TRUE;
  1540.  
  1541.                assert( strlen( stem ) + strlen( dbuff ) < MAX_COLS );
  1542.  
  1543.                strcpy( dname, stem );
  1544.                strcat( dname, dbuff );
  1545.             }
  1546.          }
  1547.       }
  1548.  
  1549.       /*
  1550.        * Go back to the current directory if needed.
  1551.        */
  1552.       if (change_directory)
  1553.          set_current_directory( cwd );
  1554.       if (window != NULL)
  1555.          redraw_screen( window );
  1556.    } else {
  1557.       /*
  1558.        * out of memory or bad dir
  1559.        */
  1560.       error( WARNING,  window != NULL ? window->bottom_line : g_display.nlines,
  1561.              dir3 );
  1562.       rc = ERROR;
  1563.    }
  1564.    return( rc );
  1565. }
  1566.  
  1567.  
  1568. /*
  1569.  * Name:    setup_directory_window
  1570.  * Purpose: set number of rows and cols in directory window
  1571.  * Date:    February 13, 1992
  1572.  * Passed:  dir: pointer to directory structure
  1573.  *          cnt: number of files
  1574.  * Notes:   set up stuff we need to know about how to display files.
  1575.  */
  1576. void setup_directory_window( DIRECTORY *dir, int cnt )
  1577. {
  1578. int  i;
  1579. int  wid;
  1580. char temp[MAX_COLS];    /* line to output */
  1581.  
  1582.    /*
  1583.     * setup the fixed vars used in dir display.
  1584.     *    dir->col =      physical upper left column of dir screen
  1585.     *    dir->row =      physical upper left row or line of dir screen
  1586.     *    dir->wid =      width of physical screen
  1587.     *    dir->hgt =      height of physical screen
  1588.     *    dir->max_cols   number of columns of files in dir screen
  1589.     *    dir->max_lines  number of lines of files in each column in dir screen
  1590.     *    dir->cnt        number of files in list
  1591.     */
  1592.    dir->col = 3;
  1593.    dir->row = 5;
  1594.    wid = dir->wid = 72;
  1595.    dir->hgt = 16;
  1596.    dir->max_cols = 5;
  1597.    dir->max_lines = 9;
  1598.    dir->cnt = cnt;
  1599.  
  1600.    /*
  1601.     * Find out how many lines in each column are needed to display
  1602.     *  matching files.
  1603.     */
  1604.    dir->lines = dir->cnt / dir->max_cols + (dir->cnt % dir->max_cols ? 1 : 0);
  1605.    if (dir->lines > dir->max_lines)
  1606.       dir->lines = dir->max_lines;
  1607.  
  1608.    /*
  1609.     * Find out how many columns of file names we need.
  1610.     */
  1611.    dir->cols = dir->cnt / dir->lines + (dir->cnt % dir->lines ? 1 : 0);
  1612.    if (dir->cols > dir->max_cols)
  1613.       dir->cols = dir->max_cols;
  1614.  
  1615.  
  1616.    /*
  1617.     * Find the maximun number of file names we can display in help screen.
  1618.     */
  1619.    dir->avail = dir->lines * dir->cols;
  1620.  
  1621.    /*
  1622.     * Now find the number of file names we do have on the screen.  Every
  1623.     *  time we slide the "window", we have to calculate a new nfiles.
  1624.     */
  1625.    dir->nfiles = dir->cnt > dir->avail ? dir->avail : dir->cnt;
  1626.  
  1627.    /*
  1628.     * A lot of times, the number of matching files will not fit evenly
  1629.     *  in our help screen.  The last column on the right will be partially
  1630.     *  filled, hence the variable name prow (partial row).  When there are
  1631.     *  more file names than can fit on the screen, we have to calculate
  1632.     *  prow every time we slide the "window" of files.
  1633.     */
  1634.    dir->prow = dir->lines - (dir->avail - dir->nfiles);
  1635.  
  1636.    /*
  1637.     * Find out how many "virtual" columns of file names we have.  If
  1638.     *  all the files can fit in the dir screen, there will be no
  1639.     *  virtual columns.
  1640.     */
  1641.    if (dir->cnt < dir->avail)
  1642.       dir->vcols = 0;
  1643.    else
  1644.       dir->vcols =  (dir->cnt - dir->avail) / dir->max_lines +
  1645.                    ((dir->cnt - dir->avail) % dir->max_lines ? 1 : 0);
  1646.  
  1647.    /*
  1648.     * Find the physical display column in dir screen.
  1649.     */
  1650.    dir->flist_col[0] = dir->col + 2;
  1651.    for (i=1; i<dir->max_cols; i++)
  1652.       dir->flist_col[i] = dir->flist_col[i-1] + 14;
  1653.  
  1654.    /*
  1655.     * Now, draw the borders of the dir screen.
  1656.     */
  1657.    for (i=0; i < dir->hgt; i++) {
  1658.       if (i == 0 || i == dir->hgt-1) {
  1659.          memset( temp, HORIZONTAL_LINE, wid );
  1660.          temp[wid] = '\0';
  1661.          if (i == 0) {
  1662.             temp[0] = CORNER_LEFT_UP;
  1663.             temp[wid-1] = CORNER_RIGHT_UP;
  1664.          } else {
  1665.             temp[0] = CORNER_LEFT_DOWN;
  1666.             temp[wid-1] = CORNER_RIGHT_DOWN;
  1667.          }
  1668.       } else {
  1669.          memset( temp, ' ', wid );
  1670.          temp[wid] = '\0';
  1671.          temp[0] = temp[wid-1] = VERTICAL_LINE;
  1672.       }
  1673.       s_output( temp, dir->row+i, dir->col, g_display.help_color );
  1674.    }
  1675.  
  1676.    /*
  1677.     * Write headings in help screen.
  1678.     */
  1679.    s_output( dir4, dir->row+DIR4_ROW, dir->col+DIR4_COL, g_display.help_color );
  1680.    s_output( dir5, dir->row+DIR5_ROW, dir->col+DIR5_COL, g_display.help_color );
  1681.    s_output( dir6, dir->row+DIR6_ROW, dir->col+DIR6_COL, g_display.help_color );
  1682.    s_output( dir7, dir->row+DIR7_ROW, dir->col+DIR7_COL, g_display.help_color );
  1683. }
  1684.  
  1685.  
  1686. /*
  1687.  * Name:    write_directory_list
  1688.  * Purpose: given directory list, display matching files
  1689.  * Date:    February 13, 1992
  1690.  * Passed:  flist: pointer to list of files
  1691.  *          dir:   directory display structure
  1692.  * Notes:   blank out the previous file name and display the new one.
  1693.  */
  1694. void write_directory_list( FTYPE *flist, DIRECTORY dir )
  1695. {
  1696. FTYPE *p, *top;
  1697. int  i;
  1698. int  j;
  1699. int  k;
  1700. int  end;
  1701. int  line;
  1702. int  col;
  1703. int  color;
  1704. char blank[20];         /* blank out file names */
  1705.  
  1706.    memset( blank, ' ', 12 );
  1707.    blank[12] = '\0';
  1708.    color = g_display.help_color;
  1709.    top = flist;
  1710.    for (i=0; i < dir.lines; ++i) {
  1711.       p = top;
  1712.       end = FALSE;
  1713.       for (j=0; j < dir.cols; ++j) {
  1714.          col = dir.flist_col[j];
  1715.          line = i + dir.row + 4;
  1716.  
  1717.          /*
  1718.           * We need to blank out all lines and columns used to display
  1719.           *  files, because there may be some residue from a previous dir
  1720.           */
  1721.          s_output( blank, line, col, color );
  1722.          if (!end) {
  1723.             s_output( p->fname, line, col, color );
  1724.             p += dir.lines;
  1725.             k = p - flist;
  1726.             if (k >= dir.nfiles)
  1727.                end = TRUE;
  1728.          }
  1729.       }
  1730.       ++top;
  1731.    }
  1732. }
  1733.  
  1734.  
  1735. /*
  1736.  * Name:    select_file
  1737.  * Purpose: To let user select a file from dir list
  1738.  * Date:    February 13, 1992
  1739.  * Passed:  flist: pointer to list of files
  1740.  *          stem:  base directory
  1741.  *          dir:   directory display stuff
  1742.  * Notes:   let user move thru the file names with the cursor keys
  1743.  */
  1744. int  select_file( FTYPE *flist, char *stem, DIRECTORY *dir )
  1745. {
  1746. int  ch;                /* input character from user */
  1747. int  func;              /* function of character input by user */
  1748. int  fno;               /* index into flist of the file under cursor */
  1749. int  goodkey;           /* is key a recognized function key? */
  1750. int  r;                 /* current row of cursor */
  1751. int  c;                 /* current column of cursor */
  1752. int  offset;            /* offset into file list */
  1753. int  stop;              /* stop indicator */
  1754. int  stem_len;          /* stem length */
  1755. int  color;             /* color of help screen */
  1756. int  file_color;        /* color of current file */
  1757. int  change;            /* boolean, hilite another file? */
  1758. int  oldr;              /* old row */
  1759. int  oldc;              /* old column */
  1760. char asize[20];         /* ascii file size */
  1761. char blank[20];         /* blank out file names */
  1762.  
  1763.    /*
  1764.     * initial everything.
  1765.     */
  1766.    memset( blank, ' ', 12 );
  1767.    blank[12] = '\0';
  1768.    c = r = 1;
  1769.    ch = fno = offset = 0;
  1770.    color = g_display.help_color;
  1771.    file_color = g_display.hilited_file;
  1772.    goodkey = TRUE;
  1773.    stop = FALSE;
  1774.    stem_len = strlen( stem );
  1775.    s_output( stem, dir->row+DIR4_ROW, dir->col+strlen( dir4 )+3, color );
  1776.    s_output( flist[fno].fname, dir->row + DIR4_ROW,
  1777.                 dir->col+strlen( dir4 )+3+stem_len, color );
  1778.    my_ltoa( flist[fno].fsize, asize, 10 );
  1779.    s_output( blank, dir->row+DIR5_ROW, dir->col+strlen( dir5 )+3, color );
  1780.    s_output( asize, dir->row+DIR5_ROW, dir->col+strlen( dir5 )+3, color );
  1781.    my_ltoa( dir->cnt,  asize, 10 );
  1782.    s_output( blank, dir->row+DIR6_ROW, dir->col+DIR6_COL+strlen( dir6 ), color);
  1783.    s_output( asize, dir->row+DIR6_ROW, dir->col+DIR6_COL+strlen( dir6 ), color);
  1784.    xygoto( (c-1)*14+dir->col+2, r+dir->row+3 );
  1785.    hlight_line( (c-1)*14+dir->col+2, r+dir->row+3, 12, file_color );
  1786.    change = FALSE;
  1787.    while (stop == FALSE) {
  1788.       oldr = r;
  1789.       oldc = c;
  1790.       ch = getkey( );
  1791.       func = getfunc( ch );
  1792.  
  1793.       /*
  1794.        * User may have redefined the Enter and ESC keys.  Make the Enter key
  1795.        *  perform a Rturn in this function. Make the ESC key do an AbortCommand.
  1796.        */
  1797.       if (ch == RTURN)
  1798.          func = Rturn;
  1799.       else if (ch == ESC)
  1800.          func = AbortCommand;
  1801.  
  1802.       switch (func) {
  1803.          case Rturn       :
  1804.          case NextLine    :
  1805.          case BegNextLine :
  1806.             stop = TRUE;
  1807.             break;
  1808.          case AbortCommand :
  1809.             stop = TRUE;
  1810.             break;
  1811.          case LineUp :
  1812.             if (r > 1) {
  1813.                change = TRUE;
  1814.                --r;
  1815.             } else {
  1816.                r = dir->lines;
  1817.                change = TRUE;
  1818.                if (offset == 0 || c > 1) {
  1819.                   if (c > 1)
  1820.                      --c;
  1821.                } else if (dir->vcols > 0 && offset > 0 && c == 1) {
  1822.                   /*
  1823.                    * recalculate the dir display stuff.
  1824.                    */
  1825.                   offset -= dir->lines;
  1826.                   recalculate_dir( dir, flist, offset );
  1827.                }
  1828.             }
  1829.             goodkey = TRUE;
  1830.             break;
  1831.          case LineDown :
  1832.             if (r < dir->prow) {
  1833.                change = TRUE;
  1834.                ++r;
  1835.             } else if (r < dir->lines && c != dir->cols) {
  1836.                change = TRUE;
  1837.                ++r;
  1838.             } else {
  1839.                change = TRUE;
  1840.                r = 1;
  1841.                if (offset == dir->vcols * dir->lines || c < dir->cols) {
  1842.                   if (c < dir->cols)
  1843.                      ++c;
  1844.                } else if (dir->vcols > 0 && offset < dir->vcols * dir->lines &&
  1845.                          c == dir->cols) {
  1846.                   offset += dir->lines;
  1847.                   recalculate_dir( dir, flist, offset );
  1848.                }
  1849.             }
  1850.             goodkey = TRUE;
  1851.             break;
  1852.          case CharLeft :
  1853.             if (offset == 0 || c > 1) {
  1854.                if (c > 1) {
  1855.                   change = TRUE;
  1856.                   --c;
  1857.                }
  1858.             } else if (dir->vcols > 0 && offset > 0 && c == 1) {
  1859.                change = TRUE;
  1860.  
  1861.                /*
  1862.                 * recalculate the dir display stuff.
  1863.                 */
  1864.                offset -= dir->lines;
  1865.                recalculate_dir( dir, flist, offset );
  1866.             }
  1867.             goodkey = TRUE;
  1868.             break;
  1869.          case CharRight :
  1870.             if (offset == dir->vcols * dir->lines || c < dir->cols) {
  1871.                if (c < dir->cols) {
  1872.                   change = TRUE;
  1873.                   ++c;
  1874.                   if (c == dir->cols) {
  1875.                      if ( r > dir->prow)
  1876.                         r = dir->prow;
  1877.                   }
  1878.                }
  1879.             } else if (dir->vcols > 0 && offset < dir->vcols * dir->lines &&
  1880.                          c == dir->cols) {
  1881.                change = TRUE;
  1882.                offset += dir->lines;
  1883.                recalculate_dir( dir, flist, offset );
  1884.                if (r > dir->prow)
  1885.                   r = dir->prow;
  1886.             }
  1887.             goodkey = TRUE;
  1888.             break;
  1889.          case BegOfLine :
  1890.             change = TRUE;
  1891.             c = r = 1;
  1892.             goodkey = TRUE;
  1893.             break;
  1894.          case EndOfLine :
  1895.             change = TRUE;
  1896.             r = dir->prow;
  1897.             c = dir->cols;
  1898.             goodkey = TRUE;
  1899.             break;
  1900.          case ScreenDown :
  1901.             change = TRUE;
  1902.             r = (c == dir->cols) ? r = dir->prow : dir->lines;
  1903.             goodkey = TRUE;
  1904.             break;
  1905.          case ScreenUp :
  1906.             change = TRUE;
  1907.             r = 1;
  1908.             goodkey = TRUE;
  1909.             break;
  1910.          default :
  1911.             break;
  1912.       }
  1913.       if (goodkey) {
  1914.          s_output( blank, dir->row+DIR4_ROW,
  1915.                    dir->col+strlen( dir4 )+3+stem_len, color );
  1916.          fno = offset + (c-1)*dir->lines + (r-1);
  1917.          s_output( flist[fno].fname, dir->row+DIR4_ROW,
  1918.                    dir->col+strlen( dir4 )+3+stem_len, color );
  1919.          my_ltoa( flist[fno].fsize, asize, 10 );
  1920.          s_output( blank, dir->row+DIR5_ROW, dir->col+strlen( dir5 )+3, color );
  1921.          s_output( asize, dir->row+DIR5_ROW, dir->col+strlen( dir5 )+3, color );
  1922.          xygoto( (c-1)*14+dir->col+2, r+dir->row+3 );
  1923.          goodkey = FALSE;
  1924.          if (change) {
  1925.             hlight_line( (oldc-1)*14+dir->col+2, oldr+dir->row+3, 12, color );
  1926.             hlight_line( (c-1)*14+dir->col+2, r+dir->row+3, 12, file_color );
  1927.             change = FALSE;
  1928.          }
  1929.       }
  1930.    }
  1931.    dir->select = fno;
  1932.    return( func == AbortCommand ? ERROR : OK );
  1933. }
  1934.  
  1935. #endif
  1936.  
  1937.  
  1938. /*
  1939.  * Name:    recalculate_dir
  1940.  * Purpose: To recalcute dir structure when cursor goes ahead or behind screen
  1941.  * Date:    November 13, 1993
  1942.  * Passed:  dir:    pointer to file structure
  1943.  *          flist:  pointer to file structure
  1944.  *          offset: number of files from beginning of flist
  1945.  * Notes:   Find new number of files on the screen.  Then, find out
  1946.  *           how many files names are in the last column.
  1947.  */
  1948. void recalculate_dir( DIRECTORY *dir , FTYPE *flist, int offset )
  1949. {
  1950. register int off;
  1951.  
  1952.    off = offset;
  1953.    dir->nfiles = (dir->cnt - off) > dir->avail ? dir->avail :
  1954.                 (dir->cnt - off);
  1955.    dir->prow = dir->lines - (dir->avail - dir->nfiles);
  1956.    write_directory_list( flist+off, *dir );
  1957. }
  1958.  
  1959.  
  1960. /*
  1961.  * Name:     shell_sort
  1962.  * Purpose:  To sort file names
  1963.  * Date:     February 13, 1992
  1964.  * Modified: November 13, 1993, Frank Davis per Byrial Jensen
  1965.  * Passed:   flist: pointer to file structure
  1966.  *           cnt:   number of files to sort
  1967.  * Notes:    this implementation of Shellsort is based on the one by Robert
  1968.  *            Sedgewick on page 109, _Algorithms in C_.
  1969.  *
  1970.  * Change:   Use of my_memcmp instead memcmp
  1971.  *           (In somes cases not-english people wants to use their own letters
  1972.  *           even in filenames; I am such one, Byrial).
  1973.  */
  1974. void shell_sort( FTYPE *flist, int cnt )
  1975. {
  1976. int  i;
  1977. register int j;
  1978. register int inc;
  1979. FTYPE temp;
  1980. FTYPE *fl;
  1981.  
  1982.    if (cnt > 1) {
  1983.  
  1984.       sort.order_array = (mode.search_case == IGNORE) ?
  1985.                               sort_order.ignore : sort_order.match;
  1986.  
  1987.       fl = flist;
  1988.  
  1989.       /*
  1990.        * figure the increments, per Donald Knuth, _Sorting and Searching_, and
  1991.        *  Robert Sedgewick, _Algorithms in C_.
  1992.        */
  1993.       j = cnt / 9;
  1994.       for (inc=1; inc <= j; inc = 3 * inc + 1);
  1995.  
  1996.       /*
  1997.        * now, Shellsort the directory file names.
  1998.        */
  1999.       for (; inc > 0; inc /= 3) {
  2000.          for (i=inc; i < cnt; i++) {
  2001.             j = i;
  2002.             memcpy( &temp, fl+j, sizeof(FTYPE) );
  2003. #if defined( __UNIX__ )
  2004.             while (j >= inc  &&  my_memcmp( (text_ptr)fl[j-inc].fname,
  2005.                                   (text_ptr)temp.fname, NAME_MAX+2 ) > 0) {
  2006.                memcpy( fl+j, fl+j-inc, sizeof(FTYPE) );
  2007.                j -= inc;
  2008.             }
  2009. #else
  2010.             while (j >= inc  &&  my_memcmp( (text_ptr)fl[j-inc].fname,
  2011.                                    (text_ptr)temp.fname, 14 ) > 0) {
  2012.                memcpy( fl+j, fl+j-inc, sizeof(FTYPE) );
  2013.                j -= inc;
  2014.             }
  2015. #endif
  2016.             memcpy( fl+j, &temp, sizeof(FTYPE) );
  2017.          }
  2018.       }
  2019.    }
  2020. }
  2021.